// List.h

// Obojsmerne zretazeny zoznam 

#ifndef LIST_H
#define LIST_H

// Sablona definuje triedu zapuzdrujucu obojsmerne zretazeny zoznam
template<class TYPE>
class List
{
public:
	class Element;

private:
	// Prvy prvok
	Element* first;
	
	// Posledny prvok
	Element* last;

	// Pocet prvkov
	int nCount;
	
public:
	// Konstruktor zoznamu
	List();

	// Destruktor zoznamu
	~List();
	// Prida prvok na koniec zoznamu
	void Add(TYPE* data);
	// Vymaze vsetky prvky zo zoznamu
	void Clear();
	// Vrati prvok, obsahujuci udaje zo vstupu
//	Element* Find(TYPE* data);
	// Skopiruje parametre zoznamu zo vstupu do tohto zoznamu a tie potom vynuluje
//	void FromList(List<TYPE>* list);
	// Vrati pocet prvkov zoznamu
	int GetCount()
	{
		return nCount;
	}
	// Vrati pointer na prvy prvok zoznamu
	Element* GetFirst()
	{ 
		return first; 
	}
	// Vrati pointer na posledny prvok zoznamu
	Element* GetLast()
	{ 
		return last;
	}
	// Vrati pointer na nasledujuci prvok zoznamu
	Element* GetNext(Element* elem)
	{
		return elem->next;
	}
	// Vrati pointer na predchadzajuci prvok zoznamu
	Element* GetPrev(Element* elem)
	{
		return elem->prev;
	}
	// Odstrani prvok s pozadovanymi udajmi
//	inline bool Remove(TYPE* data);
	// Odstrani prvok
	bool RemoveElement(Element* elem);

public:
	class Element
	{
	public:
		TYPE* data;
	
		Element* prev;
		Element* next;
	};

};

// Makro "pre kazdy prvok zoznamu"
#define LIST_FOR_EACH(type, name, list) \
	for(List<type>::Element* (name) = (list).GetFirst(); \
		(name) != NULL; \
		(name) = (list).GetNext(name))

// Konstruktor zretazeneho zoznamu
template<class TYPE>
// Pointre na prvy a posledny prvok nikde neukazuju, pocet prvkov zoznamu je na zaciatku 0
List<TYPE>::List() : first(NULL), last(NULL), nCount(0)
{

}

// Destruktor zavola funkciu Clear()
template<class TYPE>
List<TYPE>::~List()
{
	Clear();
}

// Prida prvok na koniec zoznamu
template<class TYPE> 
void List<TYPE>::Add(TYPE* data)
{
	// Vytvori novy element a naplni ho udajmi zo vstupu
	Element* elem = new Element;
	elem->data = data;
	
	// Toto sa vykona iba pri pridani prveho prvku zo zoznamu
	if(last == NULL)
	{
		// Pointre first a last zoznamu budu ukazovat na prvy pridavany prvok
		first = last = elem;
		// Pointre elementu prev a next budu ukazovat na NULL.
		elem->next = elem->prev = NULL;
	}
	// Pre vsetky prvky okrem prveho
	else
	{
		// Pointer next predchadzajuceho prvku bude ukazovat na novopridany
		last->next = elem;
		// Pointer prev novopridaneho prvku bude ukazovat na predchadzajuci
		elem->prev = last;
		// Pointer next novopridaneho prvku nebude ukazovat nikam
		elem->next = NULL;
		// Nastavi sa pointer last zoznamu, aby ukazoval na novopridany prvok
		last = elem;
	}
	// Zvacsi pocet prvkov zoznamu o 1
	nCount++;
}

// Vymaze vsetky elementy zo zoznamu
template<class TYPE>
void List<TYPE>::Clear()
{
	Element* elem;
	// Pokial nenarazime na koniec zoznamu
	while(first != NULL)
	{
		// Vymazu sa najskor udaje v elemente
		delete first->data;
		// Odlozi sa pointer na dalsi prvok zoznamu
		elem = first->next;
		// A konecne sa vymaze cely prvok
		delete first;
		// Zoznam musi ukazovat na prvy nasledujuci existujuci prvok
		first = elem;
	}
	// Vynuluje sa pocet prvkov v zozname
	nCount = 0;
}
/*
template<class TYPE>
List<TYPE>::Element* List<TYPE>::Find(TYPE* data)
{
	List<TYPE>::Element* elem = first;
	
	while(elem != NULL)
	{
		if(elem->data == data)
			return elem;
		elem = elem->next;
	}
	
	return NULL;
}
*//*
template<class TYPE>
void List<TYPE>::FromList(List<TYPE>* list)
{
	first = list->first;
	last = list->last; 
	nCount = list->nCount;

	list->first = NULL;
	list->last = NULL;
	list->nCount = 0;
}
*//*
// Odstrani prvok s pozadovanymi udajmi
template<class TYPE>
bool List<TYPE>::Remove(TYPE* data)
{
	return RemoveElement(Find(data));
}
*/
// Odstrani prvok
template<class TYPE>
bool List<TYPE>::RemoveElement(Element* elem)
{
	// Ak pointer ukazuje na neexistujuci prvok skonci
	if(elem == NULL)
		return false;
	
	// Ak neexistuje predchadzajuci prvok
	if(elem->prev == NULL)
		// Pointer first zoznamu bude ukazovat na nasledujuci prvok
		first = elem->next;
	// Inak
	else 
		// Prepoj oba prvky medzi odstranovanym prvkom
		elem->prev->next = elem->next;
	// Ak neexistuje nasledujuci prvok
	if(elem->next == NULL)
		// Pointer last zoznamu bude ukazovat na predchadzajuci prvok
		last = elem->prev;
	// Inak
	else 
		// Prepoj oba prvky medzi odstranovanym prvkom
		elem->next->prev = elem->prev;
	// Vymazu sa udaje
	if(elem->data != NULL) 
		delete elem->data;
	// Vymaze sa prvok
	delete elem;
	// Znizi sa pocet prvkov zoznamu o 1
	nCount--;
	
	return true;
}

#endif // LIST_H
